package com.augrain.microframework.core.util;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;

import java.net.*;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * IpUtils
 *
 * @author biaoy
 * @since 2020/11/25
 */
@Slf4j
public class IpUtils {
    public static final Pattern ipv4Patten =
            Pattern.compile("(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])){3}");
    private static final String UNKNOWN = "unknown";
    private static final String[] HEADERS_TO_TRY = {
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_X_FORWARDED_FOR",
            "HTTP_X_FORWARDED",
            "HTTP_X_CLUSTER_CLIENT_IP",
            "HTTP_CLIENT_IP",
            "HTTP_FORWARDED_FOR",
            "HTTP_FORWARDED",
            "HTTP_VIA",
            "REMOTE_ADDR",
            "X-Real-IP"};
    private static String LOCAL_IP = UNKNOWN;

    /**
     * 校验是否是一个ip格式，ipv4
     *
     * @param ip ipv4
     * @return true/false
     */
    public static boolean validate(String ip) {
        if (ip == null) {
            return false;
        }
        return ipv4Patten.matcher(ip).matches();
    }

    /**
     * 获取客户端ip地址(可以穿透代理)
     *
     * @param request request请求
     * @return 返回真实的ip地址
     */
    public static String getClientIpAddress(HttpServletRequest request) {
        String realIp = null;
        for (String header : HEADERS_TO_TRY) {
            String ip = request.getHeader(header);
            if (ip != null && ip.length() != 0 && !UNKNOWN.equalsIgnoreCase(ip)) {
                realIp = ip;
                break;
            }
        }
        if (realIp != null) {
            String[] ips = realIp.split(",");
            return ips[(ips.length - 1)].trim();
        }
        return request.getRemoteAddr();
    }

    public static String getRemoteIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if ((ip == null) || (ip.length() == 0) || (ip.equalsIgnoreCase(UNKNOWN))) {
            ip = request.getHeader("X-Real-IP");
        }
        if ((ip == null) || (ip.length() == 0) || (ip.equalsIgnoreCase(UNKNOWN))) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if ((ip == null) || (ip.length() == 0) || (ip.equalsIgnoreCase(UNKNOWN))) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if ((ip == null) || (ip.length() == 0) || (ip.equalsIgnoreCase(UNKNOWN))) {
            ip = request.getRemoteAddr();
        }
        if ((ip != null) && (ip.contains(","))) {
            String[] ips = ip.split(",");
            ip = ips[(ips.length - 1)].trim();
        }
        return ip;
    }

    /**
     * getRemotePort
     *
     * @param request
     * @return
     */
    public static int getRemotePort(HttpServletRequest request) {
        String port = request.getHeader("X-Forwarded-Port");
        if ((port == null) || (port.length() == 0) || (port.equalsIgnoreCase(UNKNOWN))) {
            port = request.getHeader("X-Real-Port");
        }
        if ((port == null) || (port.length() == 0) || (port.equalsIgnoreCase(UNKNOWN))) {
            port = request.getHeader("Proxy-Client-Port");
        }
        if ((port == null) || (port.length() == 0) || (port.equalsIgnoreCase(UNKNOWN))) {
            port = request.getHeader("WL-Proxy-Client-Port");
        }
        if ((port == null) || (port.length() == 0) || (port.equalsIgnoreCase(UNKNOWN))) {
            return request.getRemotePort();
        }
        try {
            return Integer.parseInt(port);
        } catch (Exception e) {
            log.info("ignore exception");
        }
        return 0;
    }

    /**
     * 获取本机，非回环、非127.0.0.1的ipv4地址
     */
    public static String getLocalIp() {
        if (LOCAL_IP.equals(UNKNOWN)) {
            synchronized (IpUtils.class) {
                if (LOCAL_IP.equals(UNKNOWN)) {
                    String[] ips = getIPS();
                    if (ips.length == 0) {
                        return "";
                    }
                    LOCAL_IP = ips[0];
                }
            }
        }
        return LOCAL_IP;
    }

    public static String[] getIPS() {
        List<String> ips = new LinkedList<>();
        try {
            Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
            InetAddress ip;
            while (netInterfaces.hasMoreElements()) {
                NetworkInterface ni = netInterfaces.nextElement();
                Enumeration<InetAddress> addresses = ni.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    ip = addresses.nextElement();
                    if (!ip.isLoopbackAddress() && ip instanceof Inet4Address) {
                        ips.add(ip.getHostAddress());
                    }
                }
            }
            return ips.toArray(new String[]{});
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 获取本机地址 格式： B4-2E-99-02-F4-D0
     */
    public static String getLocalMac() {
        try {
            String mac = getLocalMac(InetAddress.getLocalHost());
            if (mac == null) {
                String ip = getLocalIp();
                if (ip != null) {
                    InetAddress addr = InetAddress.getByName(ip);
                    if (addr != null) {
                        mac = getLocalMac(addr);
                    }
                }
            }
            return mac;
        } catch (SocketException | UnknownHostException e) {
            throw new RuntimeException(e);
        }

    }

    private static String getLocalMac(InetAddress ia) throws SocketException {
        byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
        if (mac == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append("-");
            }
            int t = mac[i] & 0xFF;
            String str = Integer.toHexString(t).toUpperCase();
            if (str.length() == 1) {
                sb.append("0").append(str);
            } else {
                sb.append(str);
            }
        }
        return sb.toString();
    }

    public static String ipToHex(String ip) {
        String[] ips = ip.split("\\.");
        StringBuilder builder = new StringBuilder();
        for (String s : ips) {
            String hex = Integer.toHexString(Integer.parseInt(s));
            builder.append(hex.length() == 1 ? "0" + hex : hex);
        }
        return builder.toString();
    }
}
